﻿using CalligraphyWeb;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Calligraphy.Models
{
    public class User
    {
        #region Data Members
        private user data;
        public user Data
        {
            get
            {
                if (data == null)
                    data = new user();

                return data;
            }
            set
            {
                if (data == value) return;
                data = value;
            }
        }
        #endregion

        #region Class Methods
        public User()
        {
        }

        public User(int id, bool isLazy = true)
        {
            Get(id, isLazy);
        }

        public User(user obj)
        {
            Get(obj);
        }
        public User Get(int id, bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = isLazy;
                var query = from c in db.users
                            where c.UserId == id
                            select c;

                if (query.Count() > 0)
                {
                    var obj = query.FirstOrDefault();
                    return Get(obj);
                }
                else
                    return null;
            }
        }

        public User Get(user obj)
        {
            if (this.data == obj) return this;

            this.data = obj;
            return this;
        }

        private long Insert()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.users.Add(data);
                db.SaveChanges();
                return data.UserId;
            }
        }

        private long Update()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.users.Attach(data);
                db.Entry(data).State = System.Data.EntityState.Modified;
                db.SaveChanges();
                return data.UserId;
            }
        }

        public long Save()
        {
            if (data.UserId == 0)
                return Insert();
            else
                return Update();
        }

        public long Delete()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.users.Remove(data);
                db.SaveChanges();
                return data.UserId;
            }
        }
        #endregion

        #region Static Methods
        public static ObservableCollection<user> Get(string sortColumn = "id", bool isAsc = false,
                                                    int pageIndex = 1, int pageSize = 10,
                                                    bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = isLazy;
                IQueryable<user> query = db.users.AsQueryable();


                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query == null)
                    return new ObservableCollection<user>();
                else
                    return new ObservableCollection<user>(query.ToList());
            }
        }

        public static List<long> Save(Collection<user> collection)
        {
            var result = new List<long>();
            foreach (var obj in collection)
            {
                var temp = new User(obj);
                result.Add(temp.Save());
            }

            return result;
        }

        public static int Delete(Collection<user> collection)
        {
            int result = 0;
            using (calligraphyEntities db = new calligraphyEntities())
            {
                foreach (var obj in collection)
                {
                    db.users.Remove(obj);
                    result++;
                }

                db.SaveChanges();
            }
            return result;
        }

        private static IQueryable<user> Sorting(IQueryable<user> query, string sortColumn = "id", bool isAsc = false)
        {
            switch (sortColumn)
            {
                case "username":
                    query = isAsc ? query.OrderBy(o => o.username) : query.OrderByDescending(o => o.username);
                    break;
                case "email":
                    query = isAsc ? query.OrderBy(o => o.email) : query.OrderByDescending(o => o.email);
                    break;
                case "firstname":
                    query = isAsc ? query.OrderBy(o => o.firstName) : query.OrderByDescending(o => o.firstName);
                    break;
                case "lastname":
                    query = isAsc ? query.OrderBy(o => o.lastName) : query.OrderByDescending(o => o.lastName);
                    break;
                case "birthday":
                    query = isAsc ? query.OrderBy(o => o.birthday) : query.OrderByDescending(o => o.birthday);
                    break;
                case "address":
                    query = isAsc ? query.OrderBy(o => o.address) : query.OrderByDescending(o => o.address);
                    break;
                case "city":
                    query = isAsc ? query.OrderBy(o => o.city) : query.OrderByDescending(o => o.city);
                    break;
                case "expired":
                    query = isAsc ? query.OrderBy(o => o.expired) : query.OrderByDescending(o => o.expired);
                    break;
                case "updated":
                case "date":
                    query = isAsc ? query.OrderBy(o => o.updated) : query.OrderByDescending(o => o.updated);
                    break;
                case "created":
                    query = isAsc ? query.OrderBy(o => o.created) : query.OrderByDescending(o => o.created);
                    break;
                case "id":
                default:
                    query = isAsc ? query.OrderBy(o => o.UserId) : query.OrderByDescending(o => o.UserId);
                    break;
            }

            return query;
        }

        private static IQueryable<user> Paging(IQueryable<user> query, int pageIndex = 1, int pageSize = 10)
        {
            if (pageIndex <= 1)
                pageIndex = 0;
            else
                pageIndex--;

            return query.Skip(pageIndex * pageSize).Take(pageSize);
        }

        public static ObservableCollection<user> Search(string username = "",
                                        string email = "", string firstname = "",
                                        string lastname = "", DateTime? birthday = null,
                                        string address = "", string city = "",
                                        DateTime? expired = null, 
                                        DateTime? createFrom = null, DateTime? createTo = null,
                                        DateTime? updateFrom = null, DateTime? updateTo = null,
                                        string sortColumn = "id", bool isAsc = false,
                                        int pageIndex = 1, int pageSize = 10,
                                        bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = isLazy;
                var query = from c in db.users
                            where (string.IsNullOrEmpty(username) ? true : c.username.ToLower().Contains(username.ToLower()))
                            && (string.IsNullOrEmpty(email) ? true : c.email.ToLower().Contains(email.ToLower()))
                            && (string.IsNullOrEmpty(firstname) ? true : c.firstName.ToLower().Contains(firstname.ToLower()))
                            && (string.IsNullOrEmpty(lastname) ? true : c.lastName.ToLower().Contains(lastname.ToLower()))
                            && (string.IsNullOrEmpty(address) ? true : c.address.ToLower().Contains(address.ToLower()))
                            && (string.IsNullOrEmpty(city) ? true : c.city.ToLower().Contains(city.ToLower()))
                            && (birthday == null ? true : birthday == c.birthday)
                            && (expired == null ? true : c.expired == expired)
                            && (createFrom == null ? true : createFrom.Value <= c.created)
                            && (createTo == null ? true : createTo.Value >= c.created)
                            && (updateFrom == null ? true : updateFrom.Value <= c.updated)
                            && (updateTo == null ? true : updateTo.Value >= c.updated)
                            select c;

                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query.Count() > 0)
                    return new ObservableCollection<user>(query.ToList());
                else
                    return new ObservableCollection<user>();
            }
        }
        #endregion
    }
}
